#include "datatrans.h"
#include <QApplication>
#include <QtNetwork/QHostAddress>
#include <QByteArray>
#include <QDataStream>
void DataRecvThread::addDataType(const QByteArray& name, int data_size, QWidget* p)
{
	data_types.insert(name, new DataType(p, data_size));
}
void DataRecvThread::setDataType(const QByteArray& name, int data_size, QWidget* p)
{
	DataType* d_type = data_types[name];
	d_type->data_size = data_size;
	d_type->parent = p;
}
void DataRecvThread::run()
{

	transfer = new DataRecv(&data_types,parent);
	exec();
	delete transfer;
	QApplication::postEvent((QObject*)parent, new QEvent(EVENT_TYPE_EXIT));
}
DataRecvThread::~DataRecvThread()
{
	QHash<QByteArray, DataType*>::const_iterator i = data_types.constBegin();
	while (i != data_types.constEnd())
	{
		delete i.value();
		++i;
	}
}
DataRecv::DataRecv(QHash<QByteArray, DataType*>* t, QMainWindow* p) :
buffer(new char[BUFFER_SIZE]), server(new QTcpServer(this)), next(1),
tid(0),table(t), parent(p), recv_client(0), heatbeat_client(0)
{
	server->listen(QHostAddress::Any);
	QApplication::postEvent((QObject*)(parent),
		new StringEvent(QString("%1").arg(server->serverPort()), EVENT_TYPE_LISTEN_PORT));
	connect(server, SIGNAL(newConnection()), this, SLOT(tcpConneted()));
	for (int i = 0; i < BUFFER_SIZE; i++)
		buffer[i] = 0;
}
void DataRecv::recvData()
{
	QTcpSocket* client = (QTcpSocket*)sender();
	QDataStream incoming(client);
	int incoming_size = client->bytesAvailable();
	incoming.readRawData(buffer, incoming_size);
	int pack_size = 0;
	for (int i = 0; i < incoming_size; i += pack_size)
	{
		DataEvent* data_event = new DataEvent(0, EVENT_TYPE_DATA);
		char* base = buffer + i;
		QByteArray data_name(base, NAME_SIZE);
		DataType* d_type = table->value(data_name);
		if (d_type == 0)return;
		pack_size = *(unsigned int*)(base + 4);
		if (d_type->parent == (QWidget*)1)
		{
			killTimer(tid);
			tid = startTimer(WAIT_HEART_BEAT_MS, Qt::VeryCoarseTimer);
			pack_size = NAME_SIZE;
			continue;
		}
		else if (d_type->parent == 0)
		{
			QDataStream out(heatbeat_client);
			out.writeRawData(base, NAME_SIZE);
			continue;
		}
		data_event->fq = *(unsigned int*)(base + 8);
		data_event->data_t = *(unsigned int*)(base + 12);
		data_event->data = d_type->getData(base + 16);
		QApplication::postEvent((QObject*)(d_type->parent), data_event);
	}
}
void DataRecv::tcpConneted()
{
	switch (next)
	{
	case 1:
		if (heatbeat_client == 0 )
		{
			heatbeat_client = server->nextPendingConnection();
			connect(heatbeat_client, SIGNAL(readyRead()), this, SLOT(recvData()));
			connect(heatbeat_client, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
			tid = startTimer(WAIT_HEART_BEAT_MS, Qt::VeryCoarseTimer);
		}
		next++;
		break;
	case 2:
		if (recv_client == 0 )
		{
			recv_client = server->nextPendingConnection();
			connect(recv_client, SIGNAL(readyRead()), this, SLOT(recvData()));
			connect(recv_client, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
		}
		next++;
		break;
	default:
		break;
	}
	if (next == 3)
	{
		QApplication::postEvent((QObject*)parent, new QEvent(EVENT_TYPE_ONLINE));
		QApplication::postEvent((QObject*)parent,
			new StringEvent(recv_client->peerAddress().toString(), EVENT_TYPE_REMOTE_IP));
		next = 1;
	}
}
void DataRecv::tcpDisconnected()
{
	QApplication::postEvent((QObject*)parent, new QEvent(EVENT_TYPE_OFFLINE));
	killTimer(tid);
	sender()->deleteLater();
	if (sender() == heatbeat_client)
		heatbeat_client = 0;
	else if (sender() == recv_client)
		recv_client = 0;
}
bool DataRecv::event(QEvent* e)
{
	switch (e->type())
	{
	case QEvent::Timer:
		QApplication::postEvent((QObject*)parent, new QEvent(EVENT_TYPE_OFFLINE));
		break;
	case EVENT_TYPE_CLOSE_TCP:
		if (heatbeat_client)heatbeat_client->close();
		if (recv_client)recv_client->close();
		QApplication::postEvent((QObject*)parent, new QEvent(EVENT_TYPE_TCP_CLOSED));
		break;
	default:
		break;
	}
	return true;
}
DataRecv::~DataRecv()
{
	delete server;
	delete[] buffer;
}
